summaryrefslogtreecommitdiffstats
path: root/src/BlockTypePalette.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/BlockTypePalette.cpp')
-rw-r--r--src/BlockTypePalette.cpp168
1 files changed, 134 insertions, 34 deletions
diff --git a/src/BlockTypePalette.cpp b/src/BlockTypePalette.cpp
index 92269db9d..b8f962f5d 100644
--- a/src/BlockTypePalette.cpp
+++ b/src/BlockTypePalette.cpp
@@ -123,7 +123,18 @@ std::map<UInt32, UInt32> BlockTypePalette::createTransformMapWithFallback(const
void BlockTypePalette::loadFromString(const AString & aString)
{
- // TODO: Detect format (Json vs Lua)
+ static const AString hdrTsvRegular = "BlockTypePalette";
+ static const AString hdrTsvUpgrade = "UpgradeBlockTypePalette";
+
+ // Detect format by checking the header line (none -> JSON):
+ if (aString.substr(0, hdrTsvRegular.length()) == hdrTsvRegular)
+ {
+ return loadFromTsv(aString, false);
+ }
+ else if (aString.substr(0, hdrTsvUpgrade.length()) == hdrTsvUpgrade)
+ {
+ return loadFromTsv(aString, true);
+ }
return loadFromJsonString(aString);
}
@@ -143,55 +154,144 @@ void BlockTypePalette::loadFromJsonString(const AString & aJsonPalette)
throw LoadFailedException(errs);
}
- // Check the JSON's metadata + version:
- if (!root.isObject() ||
- !root.isMember("Metadata") ||
- !root["Metadata"].isMember("ProtocolBlockTypePaletteVersion") ||
- !root.isMember("Palette") ||
- !root["Palette"].isArray())
- {
- throw LoadFailedException("Incorrect palette format, wrong or missing metadata.");
- }
- auto version = root["Metadata"]["ProtocolBlockTypePaletteVersion"].asUInt();
- if (version != 1)
+ // Sanity-check the JSON's structure:
+ if (!root.isObject())
{
- throw(Printf("Palette format version %d not supported.", version));
+ throw LoadFailedException("Incorrect palette format, expected an object at root.");
}
// Load the palette:
- auto len = root["Palette"].size();
- for (decltype(len) i = 0; i < len; ++i)
+ for (auto itr = root.begin(), end = root.end(); itr != end; ++itr)
{
- const auto & record = root["Palette"][i];
- if (!record.isObject())
+ const auto & blockTypeName = itr.name();
+ const auto & states = (*itr)["states"];
+ if (states == Json::Value())
{
- throw LoadFailedException(Printf("Palette record #%u is not a JSON object.", i));
+ throw LoadFailedException(Printf("Missing \"states\" for block type \"%s\"", blockTypeName));
}
+ for (const auto & state: states)
+ {
+ auto id = static_cast<UInt32>(std::stoul(state["id"].asString()));
+ std::map<AString, AString> props;
+ if (state.isMember("properties"))
+ {
+ const auto & properties = state["properties"];
+ if (!properties.isObject())
+ {
+ throw LoadFailedException(Printf("Member \"properties\" is not a JSON object (block type \"%s\", id %u).", blockTypeName, id));
+ }
+ for (const auto & key: properties.getMemberNames())
+ {
+ props[key] = properties[key].asString();
+ }
+ }
+ addMapping(id, blockTypeName, props);
+ }
+ }
+}
- auto blockTypeName = record["name"].asString();
- auto id = static_cast<UInt32>(std::stoul(record["id"].asString()));
- std::map<AString, AString> state;
- if (record.isMember("props"))
+
+
+
+void BlockTypePalette::loadFromTsv(const AString & aTsvPalette, bool aIsUpgrade)
+{
+ auto lines = StringSplitAndTrim(aTsvPalette, "\n");
+
+ // Parse the header:
+ int fileVersion = 0;
+ AString commonPrefix;
+ auto numLines = lines.size();
+ for (size_t idx = 1; idx < numLines; ++idx)
+ {
+ const auto & line = lines[idx];
+ if (line.empty())
{
- const auto & props = record["props"];
- if (!props.isObject())
+ // End of headers, erase them from lines[] and go parse the data
+ lines.erase(lines.begin(), lines.begin() + static_cast<AStringVector::difference_type>(idx) + 1);
+ break;
+ }
+ auto s = StringSplit(line, "\t");
+ if (s.size() != 2)
+ {
+ throw LoadFailedException(Printf("Invalid header format on line %u", idx + 1));
+ }
+ if (s[0] == "FileVersion")
+ {
+ try
{
- throw LoadFailedException(Printf("Palette record #%u: \"props\" value is not a JSON object.", i));
+ fileVersion = std::stoi(s[1]);
}
- for (const auto & key: props.getMemberNames())
+ catch (const std::exception & exc)
{
- state[key] = props[key].asString();
+ throw LoadFailedException(Printf("Invalid file version: \"%d\" (%s)", s[1], exc.what()));
}
}
- BlockState blockState(state);
+ else if (s[0] == "CommonPrefix")
+ {
+ commonPrefix = s[1];
+ }
+ }
+ if (fileVersion != 1)
+ {
+ throw LoadFailedException(Printf("Unknown file version (%d), only version 1 is supported", fileVersion));
+ }
- // Insert / update in the maps:
- mNumberToBlock[id] = {blockTypeName, blockState};
- mBlockToNumber[blockTypeName][blockState] = id;
- if (id > mMaxIndex)
+ // Parse the data:
+ size_t minSplit = aIsUpgrade ? 3 : 2;
+ for (const auto & line: lines)
+ {
+ auto s = StringSplit(line, "\t");
+ auto numSplit = s.size();
+ if (numSplit < minSplit)
+ {
+ throw LoadFailedException(Printf("Not enough values on data line: \"%s\"", line));
+ }
+ UInt32 id;
+ try
+ {
+ id = static_cast<UInt32>(std::stoi(s[0]));
+ }
+ catch (const std::exception & exc)
+ {
+ throw LoadFailedException(Printf("Invalid block ID: \"%s\" (%s)", s[0], exc.what()));
+ }
+ size_t idx = 1;
+ if (aIsUpgrade)
+ {
+ id = id * 16;
+ try
+ {
+ id = id + static_cast<UInt32>(Clamp(std::stoi(s[1]), 0, 15));
+ }
+ catch (const std::exception & exc)
+ {
+ throw LoadFailedException(Printf("Invalid block meta: \"%s\" (%s)", s[1], exc.what()));
+ }
+ idx = 2;
+ }
+ const auto & blockTypeName = s[idx];
+ idx += 1;
+ std::map<AString, AString> state;
+ while (idx + 1 < numSplit)
{
- mMaxIndex = id;
+ state[s[idx]] = s[idx + 1];
+ idx += 2;
}
- } // for i - Palette[]
+ addMapping(id, commonPrefix + blockTypeName, state);
+ }
+}
+
+
+
+
+
+void BlockTypePalette::addMapping(UInt32 aID, const AString & aBlockTypeName, const BlockState & aBlockState)
+{
+ mNumberToBlock[aID] = {aBlockTypeName, aBlockState};
+ mBlockToNumber[aBlockTypeName][aBlockState] = aID;
+ if (aID > mMaxIndex)
+ {
+ mMaxIndex = aID;
+ }
}